#pragma once

#include "LockGuard.hpp"
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <cstdio>
#include <string>
#include <ctime>
#include <cstdarg>
#include <pthread.h>
#include <fstream>

const std::string logname = "log.txt";

bool gIsSave = false;

// 1.日志等级
enum Level
{
  DEBUG = 0,
  INFO,
  WARNING,
  ERROR,
  FATAL
};
std::string LevelToString(int level)
{
  switch (level)
  {
  case Level::DEBUG:
    return "DEBUG";
  case Level::INFO:
    return "INFO";
  case Level::WARNING:
    return "WARNING";
  case Level::ERROR:
    return "ERROR";
  case Level::FATAL:
    return "ERROR";
  default:
    return "UNKNOWN";
  }
}

void SaveFile(const std::string &filename, const std::string &message)
{
  std::ofstream out(filename, std::ios::app);
  if (!out.is_open())
    return;
  out << message;
  out.close();
}

std::string GetTimeString()
{
  time_t cur_time = time(nullptr);
  struct tm *format_time = localtime(&cur_time);
  if (format_time == nullptr)
    return "None";
  char time_buffer[1024];
  snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",
           format_time->tm_year + 1900,
           format_time->tm_mon + 1,
           format_time->tm_mday,
           format_time->tm_hour,
           format_time->tm_min,
           format_time->tm_sec);
  return time_buffer;
}

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

// 2.日志格式
// 日志等级 时间代码所在文件名/行数 日志的内容
void LogMessage(std::string filename, int line, bool issave, int level, const char *format, ...)
{
  std::string levelstr = LevelToString(level);
  std::string timestr = GetTimeString();
  pid_t selfid = getpid();

  char buffer[1024];
  va_list arg;
  va_start(arg, format);
  vsnprintf(buffer, sizeof(buffer), format, arg);
  va_end(arg);
  LockGuard lockguard(&lock);
  std::string message = "[" + timestr + "]" + "[" + levelstr + "]" +
                        "[" + std::to_string(selfid) + "]" +
                        "[" + filename + "]" + "[" + std::to_string(line) + "] " + buffer + "\n";
  if (!issave)
  {
    std::cout << message;
  }
  else
  {
    SaveFile(logname, message);
  }
}

//__VA_ARGS__可变参数宏替换
// ##表示如果可变参数为空，则##后面的内容被忽略
// 宏标准写法
#define LOG(level, format, ...)                                            \
  do                                                                       \
  {                                                                        \
    LogMessage(__FILE__, __LINE__, gIsSave, level, format, ##__VA_ARGS__); \
  } while (0)
#define EnableFile() \
  do                 \
  {                  \
    gIsSave = true;  \
  } while (0)
#define EnableScreen() \
  do                   \
  {                    \
    gIsSave = false;   \
  } while (0)
